دليل شامل لفهم وتنفيذ برامج TypeScript الوسيطة في تطبيقات Express.js. استكشف أنماط الأنواع المتقدمة للحصول على تعليمات برمجية قوية وقابلة للصيانة.
برامج TypeScript الوسيطة: إتقان أنماط أنواع البرامج الوسيطة في Express
يسمح Express.js، وهو إطار عمل لتطبيقات الويب Node.js بسيط ومرن، للمطورين بإنشاء واجهات برمجة تطبيقات وتطبيقات ويب قوية وقابلة للتطوير. يعمل TypeScript على تحسين Express عن طريق إضافة كتابة ثابتة وتحسين قابلية صيانة التعليمات البرمجية واكتشاف الأخطاء مبكرًا. تُعد وظائف البرامج الوسيطة حجر الزاوية في Express، مما يتيح لك اعتراض الطلبات ومعالجتها قبل وصولها إلى معالجات المسار. تستكشف هذه المقالة أنماط أنواع TypeScript المتقدمة لتعريف واستخدام البرامج الوسيطة في Express، مما يعزز سلامة النوع ووضوح التعليمات البرمجية.
فهم برنامج Express الوسيط
وظائف البرامج الوسيطة هي وظائف يمكنها الوصول إلى كائن الطلب (req) وكائن الاستجابة (res) ووظيفة البرنامج الوسيط التالية في دورة طلب الاستجابة للتطبيق. يمكن لوظائف البرامج الوسيطة تنفيذ المهام التالية:
- تنفيذ أي رمز.
- إجراء تغييرات على كائني الطلب والاستجابة.
- إنهاء دورة طلب الاستجابة.
- استدعاء وظيفة البرنامج الوسيط التالية في المكدس.
يتم تنفيذ وظائف البرامج الوسيطة بالتسلسل عند إضافتها إلى تطبيق Express. تتضمن حالات الاستخدام الشائعة للبرامج الوسيطة ما يلي:
- تسجيل الطلبات.
- مصادقة المستخدمين.
- تخويل الوصول إلى الموارد.
- التحقق من صحة بيانات الطلب.
- معالجة الأخطاء.
برنامج TypeScript الوسيط الأساسي
في تطبيق TypeScript Express أساسي، قد تبدو وظيفة البرنامج الوسيط كما يلي:
import { Request, Response, NextFunction } from 'express';
function loggerMiddleware(req: Request, res: Response, next: NextFunction) {
console.log(`Request: ${req.method} ${req.url}`);
next();
}
export default loggerMiddleware;
يسجل هذا البرنامج الوسيط البسيط طريقة الطلب وعنوان URL في وحدة التحكم. دعنا نحلل تعليقات النوع:
Request: يمثل كائن طلب Express.Response: يمثل كائن استجابة Express.NextFunction: دالة تقوم، عند استدعائها، بتنفيذ البرنامج الوسيط التالي في المكدس.
يمكنك استخدام هذا البرنامج الوسيط في تطبيق Express الخاص بك كما يلي:
import express from 'express';
import loggerMiddleware from './middleware/loggerMiddleware';
const app = express();
const port = 3000;
app.use(loggerMiddleware);
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
أنماط الأنواع المتقدمة للبرامج الوسيطة
في حين أن مثال البرنامج الوسيط الأساسي عملي، إلا أنه يفتقر إلى المرونة وسلامة النوع للسيناريوهات الأكثر تعقيدًا. دعنا نستكشف أنماط الأنواع المتقدمة التي تعزز تطوير البرامج الوسيطة باستخدام TypeScript.
1. أنواع الطلبات/الاستجابات المخصصة
غالبًا ما تحتاج إلى توسيع كائني Request أو Response بخصائص مخصصة. على سبيل المثال، بعد المصادقة، قد ترغب في إضافة خاصية user إلى كائن Request. يتيح لك TypeScript زيادة الأنواع الموجودة باستخدام دمج التعريف.
// src/types/express/index.d.ts
import { Request as ExpressRequest } from 'express';
declare global {
namespace Express {
interface Request {
user?: {
id: string;
email: string;
// ... other user properties
};
}
}
}
export {}; // This is needed to make the file a module
في هذا المثال، نقوم بزيادة واجهة Express.Request لتضمين خاصية user اختيارية. الآن، في برنامج المصادقة الوسيط الخاص بك، يمكنك ملء هذه الخاصية:
import { Request, Response, NextFunction } from 'express';
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Simulate authentication logic
const userId = req.headers['x-user-id'] as string; // Or fetch from a token, etc.
if (userId) {
// In a real application, you would fetch the user from a database
req.user = {
id: userId,
email: `user${userId}@example.com`
};
next();
} else {
res.status(401).send('Unauthorized');
}
}
export default authenticationMiddleware;
وفي معالجات المسار الخاصة بك، يمكنك الوصول بأمان إلى خاصية req.user:
import express from 'express';
import authenticationMiddleware from './middleware/authenticationMiddleware';
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/profile', (req: Request, res: Response) => {
if (req.user) {
res.send(`Hello, ${req.user.email}! Your user ID is ${req.user.id}`);
} else {
// This should never happen if the middleware is working correctly
res.status(500).send('Internal Server Error');
}
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
2. مصانع البرامج الوسيطة
مصانع البرامج الوسيطة هي وظائف تُرجع وظائف البرامج الوسيطة. يكون هذا النمط مفيدًا عندما تحتاج إلى تكوين برنامج وسيط بخيارات أو تبعيات محددة. على سبيل المثال، ضع في اعتبارك برنامج تسجيل وسيط يقوم بتسجيل الرسائل في ملف معين:
import { Request, Response, NextFunction } from 'express';
import fs from 'fs';
import path from 'path';
function createLoggingMiddleware(logFilePath: string) {
return (req: Request, res: Response, next: NextFunction) => {
const logMessage = `[${new Date().toISOString()}] Request: ${req.method} ${req.url}\n`;
fs.appendFile(logFilePath, logMessage, (err) => {
if (err) {
console.error('Error writing to log file:', err);
}
next();
});
};
}
export default createLoggingMiddleware;
يمكنك استخدام مصنع البرامج الوسيطة هذا كما يلي:
import express from 'express';
import createLoggingMiddleware from './middleware/loggingMiddleware';
const app = express();
const port = 3000;
const logFilePath = path.join(__dirname, 'logs', 'requests.log');
app.use(createLoggingMiddleware(logFilePath));
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
3. برنامج وسيط غير متزامن
غالبًا ما تحتاج وظائف البرامج الوسيطة إلى تنفيذ عمليات غير متزامنة، مثل استعلامات قاعدة البيانات أو استدعاءات واجهة برمجة التطبيقات. للتعامل مع العمليات غير المتزامنة بشكل صحيح، تحتاج إلى التأكد من استدعاء وظيفة next بعد اكتمال العملية غير المتزامنة. يمكنك تحقيق ذلك باستخدام async/await أو الوعود.
import { Request, Response, NextFunction } from 'express';
async function asyncMiddleware(req: Request, res: Response, next: NextFunction) {
try {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log('Asynchronous operation completed');
next();
} catch (error) {
next(error); // Pass the error to the error handling middleware
}
}
export default asyncMiddleware;
هام: تذكر معالجة الأخطاء داخل البرنامج الوسيط غير المتزامن الخاص بك وتمريرها إلى برنامج معالجة الأخطاء الوسيط باستخدام next(error). يضمن ذلك معالجة الأخطاء وتسجيلها بشكل صحيح.
4. برنامج معالجة الأخطاء الوسيط
برنامج معالجة الأخطاء الوسيط هو نوع خاص من البرامج الوسيطة التي تعالج الأخطاء التي تحدث أثناء دورة طلب الاستجابة. تحتوي وظائف برنامج معالجة الأخطاء الوسيط على أربعة وسائط: err وreq وres وnext.
import { Request, Response, NextFunction } from 'express';
function errorHandler(err: any, req: Request, res: Response, next: NextFunction) {
console.error(err.stack);
res.status(500).send('Something went wrong!');
}
export default errorHandler;
يجب عليك تسجيل برنامج معالجة الأخطاء الوسيط بعد جميع البرامج الوسيطة الأخرى ومعالجات المسار. تحدد Express برنامج معالجة الأخطاء الوسيط من خلال وجود الوسائط الأربعة.
import express from 'express';
import asyncMiddleware from './middleware/asyncMiddleware';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(asyncMiddleware);
app.get('/', (req, res) => {
throw new Error('Simulated error!'); // Simulate an error
});
app.use(errorHandler); // Error handling middleware MUST be registered last
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
5. برنامج التحقق من صحة الطلب الوسيط
يعد التحقق من صحة الطلب جانبًا حاسمًا في بناء واجهات برمجة تطبيقات آمنة وموثوقة. يمكن استخدام البرنامج الوسيط للتحقق من صحة بيانات الطلب الواردة والتأكد من أنها تفي بمعايير معينة قبل أن تصل إلى معالجات المسار الخاصة بك. يمكن استخدام مكتبات مثل joi أو express-validator للتحقق من صحة الطلب.
إليك مثال باستخدام express-validator:
import { Request, Response, NextFunction } from 'express';
import { body, validationResult } from 'express-validator';
const validateCreateUserRequest = [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),
(req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
export default validateCreateUserRequest;
يتحقق هذا البرنامج الوسيط من صحة حقلي email وpassword في نص الطلب. إذا فشل التحقق من الصحة، فإنه يُرجع استجابة 400 Bad Request مع مجموعة من رسائل الخطأ. يمكنك استخدام هذا البرنامج الوسيط في معالجات المسار الخاصة بك كما يلي:
import express from 'express';
import validateCreateUserRequest from './middleware/validateCreateUserRequest';
const app = express();
const port = 3000;
app.post('/users', validateCreateUserRequest, (req, res) => {
// If validation passes, create the user
res.send('User created successfully!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
6. حقن التبعية للبرامج الوسيطة
عندما تعتمد وظائف البرنامج الوسيط الخاص بك على خدمات أو تكوينات خارجية، يمكن أن يساعد حقن التبعية في تحسين قابلية الاختبار والصيانة. يمكنك استخدام حاوية حقن التبعية مثل tsyringe أو ببساطة تمرير التبعيات كوسائط إلى مصانع البرنامج الوسيط الخاص بك.
إليك مثال باستخدام مصنع برنامج وسيط مع حقن التبعية:
// src/services/UserService.ts
export class UserService {
async createUser(email: string, password: string): Promise {
// In a real application, you would save the user to a database
console.log(`Creating user with email: ${email} and password: ${password}`);
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate a database operation
}
}
// src/middleware/createUserMiddleware.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/UserService';
function createCreateUserMiddleware(userService: UserService) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
const { email, password } = req.body;
await userService.createUser(email, password);
res.status(201).send('User created successfully!');
} catch (error) {
next(error);
}
};
}
export default createCreateUserMiddleware;
// src/app.ts
import express from 'express';
import createCreateUserMiddleware from './middleware/createUserMiddleware';
import { UserService } from './services/UserService';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(express.json()); // Parse JSON request bodies
const userService = new UserService();
const createUserMiddleware = createCreateUserMiddleware(userService);
app.post('/users', createUserMiddleware);
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
أفضل الممارسات لبرنامج TypeScript الوسيط
- حافظ على وظائف البرامج الوسيطة صغيرة ومركزة. يجب أن تتحمل كل وظيفة برنامج وسيط مسؤولية واحدة.
- استخدم أسماء وصفية لوظائف البرنامج الوسيط الخاص بك. يجب أن يشير الاسم بوضوح إلى ما يفعله البرنامج الوسيط.
- تعامل مع الأخطاء بشكل صحيح. قم دائمًا بالتقاط الأخطاء وتمريرها إلى برنامج معالجة الأخطاء الوسيط باستخدام
next(error). - استخدم أنواع الطلبات/الاستجابات المخصصة لتعزيز سلامة النوع. قم بزيادة واجهات
RequestوResponseبخصائص مخصصة حسب الحاجة. - استخدم مصانع البرامج الوسيطة لتكوين برنامج وسيط بخيارات محددة.
- وثق وظائف البرنامج الوسيط الخاص بك. اشرح ما يفعله البرنامج الوسيط وكيف يجب استخدامه.
- اختبر وظائف البرنامج الوسيط الخاص بك جيدًا. اكتب اختبارات الوحدة للتأكد من أن وظائف البرنامج الوسيط الخاص بك تعمل بشكل صحيح.
خاتمة
يحسن TypeScript بشكل كبير من تطوير برنامج Express الوسيط عن طريق إضافة كتابة ثابتة وتحسين قابلية صيانة التعليمات البرمجية واكتشاف الأخطاء مبكرًا. من خلال إتقان أنماط الأنواع المتقدمة مثل أنواع الطلبات/الاستجابات المخصصة ومصانع البرامج الوسيطة والبرامج الوسيطة غير المتزامنة وبرامج معالجة الأخطاء الوسيطة وبرامج التحقق من صحة الطلب الوسيطة، يمكنك إنشاء تطبيقات Express قوية وقابلة للتطوير وآمنة من النوع. تذكر اتباع أفضل الممارسات للحفاظ على وظائف البرنامج الوسيط الخاص بك صغيرة ومركزة وموثقة جيدًا.